package com.agentai.framework.websocket;

import com.alibaba.fastjson.JSONObject;
import com.agentai.framework.common.utils.IpUtils;
import com.agentai.framework.common.utils.Result;
import com.agentai.framework.satoken.cache.TokenStoreCache;
import com.agentai.framework.security.user.UserDetail;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * HttpRequest Handler.
 *
 * @since 1.0.0
 */
@Component
@ChannelHandler.Sharable
@Slf4j
public class HttpRequestHandler extends SimpleChannelInboundHandler<Object> { // （1）

	@Autowired
	WebSocketConfig webSocketConfig;

	@Autowired
	TokenStoreCache tokenStoreCache;

	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		log.info("有新的客户端链接：[{}]", ctx.channel().id().asLongText());
		// 添加到channelGroup 通道组
		NettyConfig.getChannelGroup().add(ctx.channel());
	}

	@Override
	public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
		if (msg instanceof FullHttpRequest request) {
			String uri = request.uri();
			String regex = webSocketConfig.getPath();
			if (regex.equalsIgnoreCase(uri)) {

				HttpHeaders headers = request.headers();
				String token = headers.get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL);
				String userId = ctx.channel().id().asLongText();
				boolean isAuth = webSocketConfig.isAuthEnabled();
				if(isAuth){
					log.info("Websocket连接 Token安全校验开启");
					UserDetail user = tokenStoreCache.getUser(token);
					if(null==user){
						log.info("Websocket连接 Token安全校验失败，IP:{}, Token:{}, Path = {}", IpUtils.getHostIp(), token, uri);
						ctx.channel().writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(Result.error("Token安全校验失败"))));
						ctx.close();
						return;
					}
					userId = String.valueOf(user.getId());
				}

				NettyConfig.getChannelMap().put(userId, ctx.channel());
				// 将用户ID作为自定义属性加入到channel中，方便随时channel中获取用户ID
				AttributeKey<String> key = AttributeKey.valueOf("userId");
				ctx.channel().attr(key).setIfAbsent(userId);

				// 创建 WebSocket 握手响应
				WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
						getWebSocketLocation(request), null, false);
				WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(request);

				if (handshaker == null) {
					WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
				} else {
					// 将请求头中的所有信息放入返回头中
					HttpHeaders headers2 = new DefaultHttpHeaders();
					// 设置单个头部信息
					headers2.set("Sec-WebSocket-Protocol", token);

					// 握手成功，升级协议为WebSocket
					handshaker.handshake(ctx.channel(), request, headers2, ctx.newPromise());
					log.info("websocket握手成功");
				}
			}
		} else if (msg instanceof TextWebSocketFrame textWebSocketFrame) {
//			log.info("服务器收到消息：{}", textWebSocketFrame.text());
			if (textWebSocketFrame.text().equals("ping")) {
				//心跳消息
				ctx.channel().writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(Result.ok(null, "心跳响应"))));
			} else {
				// 回复消息
				ctx.channel().writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(Result.ok())));
			}
			ctx.channel().writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(Result.ok())));
		} else {
			// 处理其他类型的帧（如关闭帧、二进制帧等）
			log.info("处理其他类型的帧（如关闭帧、二进制帧等）");
			ctx.channel().close(); // 或者其他处理逻辑
		}

	}


	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		log.info("用户下线了:{}", ctx.channel().id().asLongText());
		// 删除通道
		NettyConfig.getChannelGroup().remove(ctx.channel());
		removeUserId(ctx);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		log.info("异常：{}", cause.getMessage());
		// 删除通道
		NettyConfig.getChannelGroup().remove(ctx.channel());
		removeUserId(ctx);
		ctx.close();
	}

	/**
	 * 删除用户与channel的对应关系
	 */
	private void removeUserId(ChannelHandlerContext ctx) {
		AttributeKey<String> key = AttributeKey.valueOf("userId");
		String userId = ctx.channel().attr(key).get();
		if (StringUtils.isNotBlank(userId)) {
			NettyConfig.getChannelMap().remove(userId);
		}
	}

	private String getWebSocketLocation(FullHttpRequest req) {
		return "ws://" + req.headers().get("Host") + webSocketConfig.getPath();
	}
}
